home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Chat & Communication / Digsby build 37 / digsby_setup.exe / lib / oscar / rendezvous / filetransfer.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2008-10-13  |  21KB  |  539 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. from __future__ import with_statement
  5. __metaclass__ = type
  6. import struct
  7. import socket
  8. import time
  9. from struct import unpack, pack
  10. from pprint import pformat, pprint
  11. from util import Storage, enum, strlist, autoassign, lookup_table, removedupes, Packable, myip, FileChunker, to_hex
  12. from path import path
  13. import util
  14. import oscar
  15. import oscar.snac as oscar
  16. import oscar.OscarUtil as oscar
  17. from oscar.rendezvous.peer import OscarPeer, ipstr
  18. from oscar.rendezvous.rendezvous import oscarcookie, map_intarg, rendezvous_tlvs
  19. import oscar.capabilities as capabilities
  20. import os
  21. import os.path as os
  22. import traceback
  23. import common
  24. from logging import getLogger
  25. log = getLogger('oscar.rz.ft')
  26. info = log.info
  27.  
  28. def prettyoft(oft):
  29.     return '\n'.join((lambda .0: for line in .0:
  30. '%20s: %r' % line)(list(iter(oft))))
  31.  
  32. rz = rendezvous_tlvs
  33. tlv = oscar.OscarUtil.tlv
  34. tlv_list = oscar.OscarUtil.tlv_list
  35.  
  36. def send(oscar, screenname, filestorage):
  37.     cookie = oscarcookie()
  38.     oscar.rdv_sessions[cookie] = transfer = OutgoingOscarFileTransfer(oscar, screenname, cookie, filestorage)
  39.     transfer.request()
  40.     return transfer
  41.  
  42.  
  43. class OFTHeader(Packable):
  44.     fmt = strlist('\n        protocol_version 4s  # Always \'OFT2\'\n        length           H   # includes all data, including version and length\n        type             H   # one of "types" below\n    ')
  45.     invars = [
  46.         (lambda self: self.protocol_version == 'OFT2'),
  47.         (lambda self: self.type in self.types.values())]
  48.     types = Storage(prompt = 257, ack = 514, done = 516, receiver_resume = 517, sender_resume = 262, rcv_resume_ack = 519)
  49.  
  50.  
  51. class OFTBody(Packable):
  52.     fmt = strlist("\n    cookie              Q\n    encryption          H\n    compression         H\n    num_files           H\n    files_left          H\n    num_parts           H\n    parts_left          H\n    total_size          I\n    file_size           I\n\n    modification_time   I   # since unix epoch\n    checksum            I   # see OscarFileTransferChecksum\n    recv_fork_checksum  I\n    fork_size           I\n    creation_time       I\n    fork_checksum       I\n    bytes_received      I\n    recv_checksum       I\n    id_string           32s # 32 byte right padded string: usually 'CoolFileXfer'\n\n    flags               B   # Flags: 0x20 - Negotiation (not complete), 0x01 - Done\n    list_name_offset    B   # always 0x1c\n    list_size_offset    B   # always 0x11\n\n    dummy_block         69s # Dummy Block - large null block for future expansion of OFT\n\n    mac_file_info       16s # Mac File Info\n\n    charset             H   # charset\n    subset              H   # subset: 0 for ASCII, 2 for UTF-16BE, 3 for ISO-8859-1\n    ")
  53.     default_checksum = 0xFFFF0000L
  54.     
  55.     def padfilename(filename):
  56.         if len(filename) < 64:
  57.             filename += '\x00' * (64 - len(filename))
  58.         
  59.         return filename
  60.  
  61.     padfilename = staticmethod(padfilename)
  62.  
  63. OFTId = 'Cool FileXfer'
  64. OFTId = OFTId + '\x00' * (32 - len(OFTId))
  65.  
  66. class OscarFileTransfer(OscarPeer):
  67.     
  68.     def __init__(self, protocol, screenname, cookie):
  69.         OscarPeer.__init__(self, protocol, screenname, cookie, capabilities.by_name['file_xfer'])
  70.         common.FileTransfer.__init__(self)
  71.         self.cancelled = False
  72.         self.resuming = False
  73.         self.on_get_buddy(self.buddy)
  74.  
  75.     
  76.     def ch2cancel(self, data):
  77.         log.info('%r cancelled by buddy', self)
  78.         self.cancelled = True
  79.         self.cancel_by_buddy()
  80.         if data:
  81.             log.info('data in a ch2 cancel: %s', to_hex(data))
  82.         
  83.  
  84.     
  85.     def cancel_by_buddy(self):
  86.         log.info('cancel_by_buddy')
  87.         if self.state != self.states.CANCELLED_BY_YOU:
  88.             self.state = self.states.CANCELLED_BY_BUDDY
  89.         
  90.         
  91.         try:
  92.             self.fileobj.close()
  93.         except Exception:
  94.             import traceback as traceback
  95.             traceback.print_exc()
  96.  
  97.  
  98.     
  99.     def on_close(self):
  100.         log.info('%r on_close', self)
  101.         
  102.         try:
  103.             self.fileobj.close()
  104.         except AttributeError:
  105.             pass
  106.  
  107.         if self.state == self.states.TRANSFERRING:
  108.             self.state = self.states.CONN_FAIL_XFER
  109.             self.on_error()
  110.         
  111.  
  112.     
  113.     def close(self):
  114.         log.info('close')
  115.         
  116.         try:
  117.             self.socket.close()
  118.             del self.socket
  119.         except Exception:
  120.             pass
  121.  
  122.         self.done = True
  123.         
  124.         try:
  125.             self.fileobj.close()
  126.         except AttributeError:
  127.             pass
  128.  
  129.  
  130.     
  131.     def cancel(self, msg = '', state = None):
  132.         if hasattr(self, 'socket') and self.socket:
  133.             
  134.             try:
  135.                 self.socket.cancel_timeout()
  136.             except Exception:
  137.                 traceback.print_exc()
  138.             except:
  139.                 None<EXCEPTION MATCH>Exception
  140.             
  141.  
  142.         None<EXCEPTION MATCH>Exception
  143.         
  144.         try:
  145.             self.filechunker.cancelled = True
  146.         except Exception:
  147.             traceback.print_exc()
  148.             info('$$$ sending cancel')
  149.             self.send_rdv('cancel')
  150.  
  151.         self.close()
  152.         self.setnotifyif('cancelled', True)
  153.         info('%r cancelled. %s', self, msg)
  154.         if state is None:
  155.             state = self.states.CANCELLED_BY_YOU
  156.         
  157.         self.state = state
  158.  
  159.     
  160.     def ch2accept(self, data):
  161.         if data:
  162.             log.error('got data in a channel 2 accept: data = %r', data)
  163.             self.cancel()
  164.         else:
  165.             log.info('ch2accept data = %r', data)
  166.  
  167.     
  168.     def decline_transfer(self, reason = None):
  169.         log.info('decline_transfer: reason = %r', reason)
  170.         self.cancel()
  171.  
  172.     
  173.     def send_oft(self, type, setvalues = True):
  174.         oft = self.oft
  175.         if not oft:
  176.             return None
  177.         
  178.         if setvalues:
  179.             oft.id_string = OFTId
  180.             oft.cookie = self.cookie
  181.             oft.list_name_offset = 28
  182.             oft.list_size_offset = 17
  183.             oft.flags = None if 'type' == 'done' else 32
  184.             oft.checksum = OFTBody.default_checksum
  185.         
  186.         info('sending oft %s for %s', type, self.filename)
  187.         info(prettyoft(oft) + '\n  filename: %s', self.filename)
  188.         self.socket.push(oftpacket(type, oft, self.filename))
  189.  
  190.  
  191.  
  192. class OutgoingOscarFileTransfer(OscarFileTransfer, common.OutgoingFileTransfer):
  193.     
  194.     def __init__(self, o, screenname, cookie, fileinfo):
  195.         OscarFileTransfer.__init__(self, o, screenname, cookie)
  196.         [ setattr(self, a, fileinfo[a]) for a in 'name files size numfiles'.split() ]
  197.         self.filepath = path(fileinfo.path)
  198.         self.fileobj = None
  199.         self.oft = self.next_file()
  200.         self.accepted = False
  201.         self.connected = False
  202.         self.completed = 0
  203.         self.state = self.states.WAITING_FOR_BUDDY
  204.  
  205.     
  206.     def next_file(self):
  207.         if self.files:
  208.             self.file = self.files.pop(0)
  209.             if hasattr(self, 'rootpath'):
  210.                 p = self.rootpath.relpathto(self.file)
  211.                 self.filename = p.normpath().replace('\\', '/').replace('/', chr(1))
  212.             else:
  213.                 self.filename = self.file.name
  214.             return self.oft_for_file(self.file)
  215.         else:
  216.             self.file = None
  217.             return False
  218.  
  219.     
  220.     def __repr__(self):
  221.         if not getattr(self.file, 'name', None):
  222.             pass
  223.         return '<OutgoingOscarFileTransfer to %s (%s)>' % (self.screenname, '')
  224.  
  225.     
  226.     def request(self, message = '<html>'):
  227.         xdata = xdata_block(self.name, self.size, self.numfiles)
  228.         self.establish_out_dc(message = message, extratlvs = [
  229.             (rz.extended_data, xdata),
  230.             (rz.filename_encoding, 'us-ascii')])
  231.  
  232.     
  233.     def on_odc_connection(self):
  234.         info('%r connected!', self)
  235.         self.connected = True
  236.         self.maybe_start()
  237.  
  238.     
  239.     def received_oft_header(self, data):
  240.         (header, data) = OFTHeader.unpack(data)
  241.         log.debug('received OFT header: oft=%(protocol_version)s length=0x%(length)x type=0x%(type)x', dict(header))
  242.         bytes_left = header.length - OFTHeader._struct.size
  243.         if header.type in (OFTHeader.types.ack, OFTHeader.types.rcv_resume_ack):
  244.             self.open_file()
  245.         elif header.type == OFTHeader.types.done:
  246.             
  247.             try:
  248.                 self.fileobj.close()
  249.             except AttributeError:
  250.                 pass
  251.  
  252.             self.fileobj = None
  253.             self.oft = self.next_file()
  254.             if not self.oft:
  255.                 if self.completed:
  256.                     self.state = self.states.FINISHED
  257.                     self._ondone()
  258.                 else:
  259.                     self.cancel_by_buddy()
  260.                 self.close()
  261.             
  262.             return None
  263.         elif header.type == OFTHeader.types.receiver_resume:
  264.             log.info('Going to resume file %s' % self.file)
  265.             self.resuming = True
  266.         else:
  267.             log.warning('Error! OFT type %r', header.type)
  268.         self.socket.receive_next(bytes_left, self.received_oft_body)
  269.  
  270.     
  271.     def open_file(self):
  272.         
  273.         try:
  274.             self.fileobj = self.file.open('rb')
  275.             return True
  276.         except IOError:
  277.             self.cancel('Could not open file %s' % self.file)
  278.             return False
  279.  
  280.  
  281.     
  282.     def received_oft_body(self, data):
  283.         (oft, data) = OFTBody.unpack(data)
  284.         (filename, data) = read_cstring(data)
  285.         info(prettyoft(oft) + '\n  filename: %s', filename)
  286.         self.oft = oft
  287.         self.socket.receive_next(OFTHeader, self.received_oft_header)
  288.         if self.fileobj:
  289.             if self.resuming:
  290.                 self.fileobj.seek(oft.bytes_received)
  291.                 self._setcompleted(self.fileobj.tell())
  292.             
  293.             self.filechunker = FileChunker(self.fileobj, close_when_done = True, progress_cb = self._setcompleted)
  294.             log.info('Pushing FileChunker onto socket')
  295.             self.socket.push_with_producer(self.filechunker)
  296.         elif self.oft:
  297.             if self.resuming:
  298.                 self.send_oft('sender_resume', False)
  299.             else:
  300.                 self.send_oft('prompt')
  301.         else:
  302.             info('DONE!')
  303.             self.state = self.states.FINISHED
  304.             self.close()
  305.  
  306.     
  307.     def ch2accept(self, data):
  308.         info('received CH2 accept')
  309.         self.accepted = True
  310.         self.maybe_start()
  311.  
  312.     
  313.     def maybe_start(self):
  314.         if not (self.accepted) or not (self.connected):
  315.             if not self.accepted:
  316.                 info('no RDV accept yet')
  317.             
  318.             if not self.connected:
  319.                 info('no connection yet')
  320.             
  321.             return None
  322.         
  323.         self.state = self.states.TRANSFERRING
  324.         if not getattr(self, 'sent_first', False):
  325.             info('sending first oft prompt')
  326.             self.sent_first = True
  327.             self.send_oft('prompt')
  328.         
  329.         self.socket.receive_next(OFTHeader, self.received_oft_header)
  330.  
  331.     
  332.     def oft_for_file(self, file):
  333.         return OFTBody(cookie = self.cookie, num_files = self.numfiles, files_left = 1 + len(self.files), num_parts = 1, parts_left = 1, total_size = self.size, file_size = file.size, modification_time = int(file.mtime), creation_time = int(file.ctime), checksum = OFTBody.default_checksum, recv_fork_checksum = OFTBody.default_checksum, fork_checksum = OFTBody.default_checksum, recv_checksum = OFTBody.default_checksum, id_string = OFTId, dummy_block = '\x00' * 69, mac_file_info = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', charset = 0, subset = 0)
  334.  
  335.  
  336.  
  337. class IncomingOscarFileTransfer(OscarFileTransfer, common.IncomingFileTransfer):
  338.     direction = 'incoming'
  339.     
  340.     def __init__(self, o, screenname, cookie):
  341.         OscarFileTransfer.__init__(self, o, screenname, cookie)
  342.         self.completed = 0
  343.  
  344.     
  345.     def handle_request(self, rendtlvs):
  346.         (info, data) = unpack_extended_data(rendtlvs.extended_data)
  347.         self.__dict__.update(info)
  348.         self._onrequest()
  349.  
  350.     
  351.     def accept(self, file_obj):
  352.         if self.cancelled:
  353.             e = OscarFileTransferError('The sender has already cancelled this file request.')
  354.             self.protocol.hub.on_error(e)
  355.         elif isinstance(file_obj, file) or self.numfiles == 1:
  356.             self.filepath = path(file_obj.name)
  357.             self.rootpath = self.filepath.parent
  358.             file_obj.close()
  359.         else:
  360.             self.rootpath = os.path.join(file_obj, self.name)
  361.             if not os.path.exists(self.rootpath):
  362.                 os.makedirs(self.rootpath)
  363.             
  364.             self.filepath = path(self.rootpath)
  365.         info('self.rootpath = %r', self.rootpath)
  366.         None(info, 'accepting incoming file transfer, saving %s to %s' if self.numfiles == 1 else 'files', self.rootpath)
  367.         self.state = self.states.CONNECTING
  368.         self.establish_dc()
  369.  
  370.     
  371.     def decline(self):
  372.         self.state = self.states.CANCELLED_BY_YOU
  373.         self.send_rdv('cancel')
  374.         common.IncomingFileTransfer.decline(self)
  375.  
  376.     
  377.     def on_odc_connection(self):
  378.         self.state = self.states.TRANSFERRING
  379.         self.socket.receive_next(OFTHeader, self.received_oft_header)
  380.  
  381.     
  382.     def received_oft_header(self, data):
  383.         (header, data) = OFTHeader.unpack(data)
  384.         log.debug('received OFT header: %r', dict(header))
  385.         if header.type == OFTHeader.types.prompt:
  386.             bytes_left = header.length - OFTHeader._struct.size
  387.             log.debug('receiving %d more OFT body bytes', bytes_left)
  388.             self.socket.receive_next(bytes_left, self.received_oft_body)
  389.         else:
  390.             self.fail('Error! OFT type ' + str(header.type))
  391.  
  392.     
  393.     def received_oft_body(self, data):
  394.         (oft, data) = OFTBody.unpack(data)
  395.         self.oft = oft
  396.         info('incoming oft body...\n' + prettyoft(oft))
  397.         nullindex = data.find('\x00')
  398.         if nullindex == -1:
  399.             raise AssertionError("couldn't find a null byte in the padded filename")
  400.         
  401.         self.filename = filename = data[:nullindex]
  402.         self.fileobj = openpath(self.rootpath, self.filepath.name)
  403.         info('incoming file: %s (%d bytes), %d left', filename, oft.file_size, oft.files_left)
  404.         self.send_oft('ack')
  405.         self.socket.push_collector(self.collect_file_bytes)
  406.         if oft.file_size > 0:
  407.             self.socket.receive_next(oft.file_size, self.received_file)
  408.         else:
  409.             self.received_file()
  410.  
  411.     
  412.     def collect_file_bytes(self, data):
  413.         
  414.         try:
  415.             self.fileobj.write(data)
  416.         except IOError:
  417.             import traceback
  418.             traceback.print_exc()
  419.             return None
  420.         else:
  421.             self._setcompleted(self.fileobj.tell())
  422.         finally:
  423.             self.data = ''
  424.  
  425.  
  426.     
  427.     def received_file(self, *data):
  428.         self.socket.pop_collector()
  429.         info('received file %s', self.fileobj.name)
  430.         self.fileobj.close()
  431.         self.send_oft('done')
  432.         if self.oft.files_left == 1:
  433.             info('done!')
  434.             self.socket.close()
  435.             self._ondone()
  436.         else:
  437.             self.socket.receive_next(OFTHeader, self.received_oft_header)
  438.  
  439.     
  440.     def fail(self, msg):
  441.         log.error(msg)
  442.         self.close()
  443.  
  444.     
  445.     def __repr__(self):
  446.         return '<IncomingOFT from %s>' % self.screenname
  447.  
  448.  
  449.  
  450. def oftpacket(type, body, filename):
  451.     filename = str(filename)
  452.     padded = OFTBody.padfilename(filename)
  453.     return ''.join([
  454.         OFTHeader('OFT2', length = 192 + len(padded), type = map_intarg(type, OFTHeader.types)).pack(),
  455.         body.pack(),
  456.         padded])
  457.  
  458.  
  459. def oft_filename(fn):
  460.     fn += chr(0)
  461.     if len(fn) < 64:
  462.         fn += (64 - len(fn)) * chr(0)
  463.     
  464.     return fn
  465.  
  466.  
  467. def read_cstring(data):
  468.     i = data.find(chr(0))
  469.     if i == -1:
  470.         raise ValueError('not a null terminated string')
  471.     
  472.     return (data[:i], data[i + 1:])
  473.  
  474.  
  475. def unpack_extended_data(data):
  476.     (multiple, filecount, totalbytes) = struct.unpack('!HHI', data[:8])
  477.     data = data[8:]
  478.     (filename, data) = read_cstring(data)
  479.     return (util.Storage(numfiles = filecount, multiple = multiple == 2, size = totalbytes, name = filename), data)
  480.  
  481.  
  482. def xdata_block(filename, filesize, filecount = 1):
  483.     return None(struct.pack, '!HHI' if filecount == 1 else 2, filecount, filesize) + filename.encode('utf-8') + '\x00'
  484.  
  485.  
  486. def openpath(rootpath, filename):
  487.     PATHSEP = chr(1)
  488.     needdirs = filename.find(PATHSEP) != -1
  489.     path = filename.split(PATHSEP)
  490.     filename = path.pop(-1)
  491.     path = [
  492.         rootpath] + path
  493.     if needdirs:
  494.         pathstr = os.path.join(*path)
  495.         if not os.path.exists(pathstr):
  496.             info('calling makedirs(%s)', pathstr)
  497.             os.makedirs(pathstr)
  498.         
  499.     
  500.     filepath = path + [
  501.         filename]
  502.     return open(os.path.join(*filepath), 'wb')
  503.  
  504.  
  505. class OscarFileTransferError(Exception):
  506.     pass
  507.  
  508.  
  509. class OFTChecksum(object):
  510.     starting_value = 0xFFFF0000L
  511.     
  512.     def __init__(self, data = None):
  513.         self.checksum = self.starting_value
  514.         if data is not None:
  515.             self.update(data)
  516.         
  517.  
  518.     
  519.     def update(self, data, offset = 0):
  520.         check = self.checksum >> 16 & 0xFFFFL
  521.         for i in xrange(len(data)):
  522.             oldcheck = check
  523.             byteval = ord(data[offset + i]) & 255
  524.             None -= check if i & 1 != 0 else byteval << 8
  525.             if check > oldcheck:
  526.                 check -= 1
  527.                 continue
  528.         
  529.         check = (check & 65535) + (check >> 16)
  530.         check = (check & 65535) + (check >> 16)
  531.         checksum = check << 16 & 0xFFFFFFFFL
  532.  
  533.  
  534. if __name__ == '__main__':
  535.     p = 'c:\\users\\kevin\\desktop\\apple_evolution.jpg'
  536.     bytes = open(p, 'rb').read()
  537.     print OFTChecksum(bytes).checksum
  538.  
  539.